<?php
/**
 * AWS S3协议客户端类
 * 支持各大云服务商的对象存储服务
 * 
 * @package CommonCloudStorage
 * @author xiaogg
 * @version 1.0
 */

if (!defined('ZBP_PATH')) {
    exit('Access denied');
}

/**
 * S3上传文件
 */
function CommonCloudStorage_S3_Upload($cloudPath, $localFile, $config) {
    try {
        // 使用指定的云存储路径
        $key = $cloudPath;
        
        // 读取文件内容
        $fileContent = file_get_contents($localFile);
        if ($fileContent === false) {
            throw new Exception('无法读取文件: ' . $localFile);
        }
        
        // 获取文件MIME类型
        $mimeType = CommonCloudStorage_GetMimeType($localFile);
        
        // 构建S3请求
        $result = CommonCloudStorage_S3_PutObject($config, $key, $fileContent, $mimeType);
        
        if ($result['success']) {
            // 记录上传日志
            CommonCloudStorage_Log('S3上传成功: ' . $key);
            return true;
        } else {
            CommonCloudStorage_Log('S3上传失败: ' . $result['error']);
            return false;
        }
        
    } catch (Exception $e) {
        CommonCloudStorage_Log('S3上传异常: ' . $e->getMessage());
        return false;
    }
}

/**
 * S3删除文件
 */
function CommonCloudStorage_S3_Delete($localFile, $config) {
    try {
        $relativePath = str_replace($GLOBALS['zbp']->path, '', $localFile);
        $relativePath = str_replace('\\', '/', $relativePath);
        $key = ltrim($relativePath, '/');
        
        // 构建S3删除请求
        $result = CommonCloudStorage_S3_DeleteObject($config, $key);
        
        if ($result['success']) {
            CommonCloudStorage_Log('S3删除成功: ' . $key);
            return true;
        } else {
            CommonCloudStorage_Log('S3删除失败: ' . $result['error']);
            return false;
        }
        
    } catch (Exception $e) {
        CommonCloudStorage_Log('S3删除异常: ' . $e->getMessage());
        return false;
    }
}

/**
 * S3连接测试
 */
function CommonCloudStorage_S3_Test($config) {
    try {
        // 尝试列出存储桶内容
        $result = CommonCloudStorage_S3_ListObjects($config);
        
        if ($result['success']) {
            return array('success' => true, 'message' => 'S3连接成功');
        } else {
            return array('success' => false, 'message' => $result['error']);
        }
        
    } catch (Exception $e) {
        return array('success' => false, 'message' => $e->getMessage());
    }
}

/**
 * S3 PUT Object操作
 */
function CommonCloudStorage_S3_PutObject($config, $key, $content, $contentType = 'application/octet-stream') {
    // 构建endpoint和URL
    $urlInfo = CommonCloudStorage_BuildS3Url($config, $key);
    $url = $urlInfo['url'];
    $host = $urlInfo['host'];
    $path = $urlInfo['path'];
    
    // 构建请求头
    $headers = array(
        'Host' => $host,
        'Content-Type' => $contentType,
        'Content-Length' => strlen($content),
        'x-amz-content-sha256' => hash('sha256', $content),
        'x-amz-date' => gmdate('Ymd\THis\Z')
    );
    
    // AWS签名v4
    $signature = CommonCloudStorage_S3_SignatureV4_New('PUT', $host, $path, '', $headers, $content, $config);
    $headers['Authorization'] = $signature;
    
    // 发送HTTP请求
    $result = CommonCloudStorage_HttpRequest('PUT', $url, $headers, $content);
    
    if ($result['http_code'] >= 200 && $result['http_code'] < 300) {
        return array('success' => true);
    } else {
        return array('success' => false, 'error' => 'HTTP ' . $result['http_code'] . ': ' . $result['body']);
    }
}

/**
 * S3 DELETE Object操作
 */
function CommonCloudStorage_S3_DeleteObject($config, $key) {
    $urlInfo = CommonCloudStorage_BuildS3Url($config, $key);
    $url = $urlInfo['url'];
    $host = $urlInfo['host'];
    $path = $urlInfo['path'];
    
    $headers = array(
        'Host' => $host,
        'x-amz-content-sha256' => hash('sha256', ''),
        'x-amz-date' => gmdate('Ymd\THis\Z')
    );
    
    $signature = CommonCloudStorage_S3_SignatureV4_New('DELETE', $host, $path, '', $headers, '', $config);
    $headers['Authorization'] = $signature;
    
    $result = CommonCloudStorage_HttpRequest('DELETE', $url, $headers);
    
    if ($result['http_code'] >= 200 && $result['http_code'] < 300) {
        return array('success' => true);
    } else {
        return array('success' => false, 'error' => 'HTTP ' . $result['http_code'] . ': ' . $result['body']);
    }
}

/**
 * S3 LIST Objects操作（用于测试连接）
 */
function CommonCloudStorage_S3_ListObjects($config) {
    $urlInfo = CommonCloudStorage_BuildS3Url($config, '', 'max-keys=1');
    $url = $urlInfo['url'];
    $host = $urlInfo['host'];
    $path = $urlInfo['path'];
    $query = 'max-keys=1';
    
    // 使用更标准的时间戳格式
    $amzDate = gmdate('Ymd\THis\Z');
    $dateStamp = substr($amzDate, 0, 8);
    
    $headers = array(
        'Host' => $host,
        'x-amz-content-sha256' => hash('sha256', ''),
        'x-amz-date' => $amzDate
    );
    
    // 添加调试日志
    CommonCloudStorage_Log("S3 ListObjects调试信息:");
    CommonCloudStorage_Log("URL: " . $url);
    CommonCloudStorage_Log("Host: " . $host);
    CommonCloudStorage_Log("Path: " . $path);
    CommonCloudStorage_Log("Query: " . $query);
    CommonCloudStorage_Log("Headers: " . json_encode($headers));
    
    $signature = CommonCloudStorage_S3_SignatureV4_New('GET', $host, $path, $query, $headers, '', $config);
    $headers['Authorization'] = $signature;
    
    CommonCloudStorage_Log("Authorization: " . $signature);
    
    $result = CommonCloudStorage_HttpRequest('GET', $url, $headers);
    
    CommonCloudStorage_Log("HTTP响应码: " . $result['http_code']);
    CommonCloudStorage_Log("响应体: " . $result['body']);
    CommonCloudStorage_Log("错误信息: " . $result['error']);
    
    if ($result['http_code'] >= 200 && $result['http_code'] < 300) {
        return array('success' => true);
    } else {
        return array('success' => false, 'error' => 'HTTP ' . $result['http_code'] . ': ' . $result['body']);
    }
}

/**
 * 获取S3 Endpoint
 */
function CommonCloudStorage_GetS3Endpoint($config) {
    // 优先使用自定义端点
    if (!empty($config['endpoint'])) {
        return rtrim($config['endpoint'], '/');
    }
    
    // 其次使用存储桶域名
    if (!empty($config['bucket_domain'])) {
        return 'https://' . rtrim($config['bucket_domain'], '/');
    }
    
    // 最后使用默认AWS S3 endpoint
    $region = $config['region'] ?: 'us-east-1';
    return 'https://s3.' . $region . '.amazonaws.com';
}

/**
 * 构建S3 URL和相关信息
 */
function CommonCloudStorage_BuildS3Url($config, $key = '', $query = '') {
    $bucket = $config['bucket_name'];
    $endpoint = CommonCloudStorage_GetS3Endpoint($config);
    
    // 移除协议部分获取host
    $parsedEndpoint = parse_url($endpoint);
    $host = $parsedEndpoint['host'];
    $scheme = $parsedEndpoint['scheme'] ?: 'https';
    
    // 判断是否使用路径风格或虚拟主机风格
    $usePathStyle = CommonCloudStorage_ShouldUsePathStyle($config);
    
    if ($usePathStyle) {
        // 路径风格: https://endpoint/bucket/key
        $path = '/' . $bucket . ($key ? '/' . $key : '');
        $url = $scheme . '://' . $host . $path;
    } else {
        // 虚拟主机风格: https://bucket.endpoint/key
        $host = $bucket . '.' . $host;
        $path = $key ? '/' . $key : '/';
        $url = $scheme . '://' . $host . $path;
    }
    
    if ($query) {
        $url .= '?' . $query;
    }
    
    return array(
        'url' => $url,
        'host' => $host,
        'path' => $path
    );
}

/**
 * 判断是否应使用路径风格
 */
function CommonCloudStorage_ShouldUsePathStyle($config) {
    // 对于第三方S3服务，默认使用路径风格（更稳定）
    if (!empty($config['endpoint'])) {
        return true; // 第三方服务使用路径风格
    }
    
    // 检查是否为AWS S3
    $endpoint = CommonCloudStorage_GetS3Endpoint($config);
    if (strpos($endpoint, 'amazonaws.com') !== false) {
        return false; // AWS S3使用虚拟主机风格
    }
    
    // 其他情况默认使用路径风格
    return true;
}

/**
 * AWS签名v4算法
 */
function CommonCloudStorage_S3_SignatureV4($method, $url, $headers, $payload, $config) {
    $accessKey = $config['access_key'];
    $secretKey = $config['secret_key'];
    $region = $config['region'] ?: 'us-east-1';
    $service = 's3';
    
    $parsedUrl = parse_url($url);
    $host = $parsedUrl['host'];
    $path = $parsedUrl['path'] ?: '/';
    $query = isset($parsedUrl['query']) ? $parsedUrl['query'] : '';
    
    $timestamp = $headers['x-amz-date'];
    $date = substr($timestamp, 0, 8);
    
    // 规范化请求
    $canonicalHeaders = '';
    $signedHeaders = '';
    $headerNames = array();
    
    $headers['host'] = $host;
    
    foreach ($headers as $name => $value) {
        $name = strtolower($name);
        $headerNames[] = $name;
        $canonicalHeaders .= $name . ':' . trim($value) . "\n";
    }
    
    sort($headerNames);
    $signedHeaders = implode(';', $headerNames);
    
    $canonicalRequest = $method . "\n" .
                       $path . "\n" .
                       $query . "\n" .
                       $canonicalHeaders . "\n" .
                       $signedHeaders . "\n" .
                       hash('sha256', $payload);
    
    // 创建签名字符串
    $algorithm = 'AWS4-HMAC-SHA256';
    $credentialScope = $date . '/' . $region . '/' . $service . '/aws4_request';
    $stringToSign = $algorithm . "\n" .
                   $timestamp . "\n" .
                   $credentialScope . "\n" .
                   hash('sha256', $canonicalRequest);
    
    // 计算签名
    $kDate = hash_hmac('sha256', $date, 'AWS4' . $secretKey, true);
    $kRegion = hash_hmac('sha256', $region, $kDate, true);
    $kService = hash_hmac('sha256', $service, $kRegion, true);
    $kSigning = hash_hmac('sha256', 'aws4_request', $kService, true);
    $signature = hash_hmac('sha256', $stringToSign, $kSigning);
    
    // 构建Authorization头 - 修正区域和服务名称
    $authorization = $algorithm . ' ' .
                    'Credential=' . $accessKey . '/' . $credentialScope . ', ' .
                    'SignedHeaders=' . $signedHeaders . ', ' .
                    'Signature=' . $signature;
    
    // 调试日志
    CommonCloudStorage_Log("签名调试信息:");
    CommonCloudStorage_Log("算法: " . $algorithm);
    CommonCloudStorage_Log("访问密钥: " . $accessKey);
    CommonCloudStorage_Log("凭证范围: " . $credentialScope);
    CommonCloudStorage_Log("已签名头部: " . $signedHeaders);
    CommonCloudStorage_Log("签名: " . $signature);
    CommonCloudStorage_Log("完整Authorization头: " . $authorization);
    
    return $authorization;
}

/**
 * AWS签名v4算法 - 修正版，解决SignatureDoesNotMatch错误
 */
function CommonCloudStorage_S3_SignatureV4_New($method, $host, $path, $query, $headers, $payload, $config) {
    $accessKey = $config['access_key'];
    $secretKey = $config['secret_key'];
    // 确保区域格式正确，避免使用存储桶名称
    $region = isset($config['region']) && !empty($config['region']) ? $config['region'] : 'us-east-1';
    $service = 's3';
    
    $timestamp = $headers['x-amz-date'];
    $date = substr($timestamp, 0, 8);
    
    // 规范化查询字符串 - 参考OpenList的实现
    $canonicalQuery = '';
    if ($query) {
        parse_str($query, $queryParams);
        ksort($queryParams);
        $queryParts = array();
        foreach ($queryParams as $key => $value) {
            // 使用更严格的URL编码，替换+为%20
            $encodedKey = str_replace('+', '%20', rawurlencode($key));
            $encodedValue = str_replace('+', '%20', rawurlencode($value));
            $queryParts[] = $encodedKey . '=' . $encodedValue;
        }
        $canonicalQuery = implode('&', $queryParts);
    }
    
    // 规范化请求头 - 包含所有头部
    $canonicalHeaders = '';
    $signedHeaders = '';
    $headerNames = array();
    $normalizedHeaders = array();
    
    // 不可签名的头部列表（参考OpenList）
    $unsignableHeaders = array(
        'authorization' => true,
        'content-type' => true,
        'content-length' => true,
        'user-agent' => true,
        'presigned-expires' => true,
        'expect' => true,
        'x-amzn-trace-id' => true
    );
    
    // 包含所有可签名的头部
    foreach ($headers as $name => $value) {
        $lowerName = strtolower(trim($name));
        $trimmedValue = trim($value);
        
        // 检查是否可签名
        if (strpos($lowerName, 'x-amz-') === 0 || !isset($unsignableHeaders[$lowerName])) {
            $normalizedValue = preg_replace('/\s+/', ' ', $trimmedValue);
            $normalizedHeaders[$lowerName] = $normalizedValue;
            $headerNames[] = $lowerName;
        }
    }
    
    sort($headerNames);
    $signedHeaders = implode(';', $headerNames);
    
    foreach ($headerNames as $name) {
        $canonicalHeaders .= $name . ':' . $normalizedHeaders[$name] . "\n" ;
    }
    
    // 规范化请求 - 使用正确的换行符
    $canonicalRequest = $method . "\n" .
                       $path . "\n" .
                       $canonicalQuery . "\n" .
                       $canonicalHeaders . "\n" .
                       $signedHeaders . "\n" .
                       hash('sha256', $payload);
    
    // 创建签名字符串
    $algorithm = 'AWS4-HMAC-SHA256';
    $credentialScope = $date . '/' . $region . '/' . $service . '/aws4_request';
    $stringToSign = $algorithm . "\n" .
                   $timestamp . "\n" .
                   $credentialScope . "\n" .
                   hash('sha256', $canonicalRequest);
    
    // 计算签名 - 使用正确的HMAC计算方式
    $kDate = hash_hmac('sha256', $date, 'AWS4' . $secretKey, true);
    $kRegion = hash_hmac('sha256', $region, $kDate, true);
    $kService = hash_hmac('sha256', $service, $kRegion, true);
    $kSigning = hash_hmac('sha256', 'aws4_request', $kService, true);
    $signature = hash_hmac('sha256', $stringToSign, $kSigning, true);
    $signature = bin2hex($signature);
    
    // 调试签名计算过程
    CommonCloudStorage_Log("签名计算调试:");
    CommonCloudStorage_Log("kDate: " . bin2hex($kDate));
    CommonCloudStorage_Log("kRegion: " . bin2hex($kRegion));
    CommonCloudStorage_Log("kService: " . bin2hex($kService));
    CommonCloudStorage_Log("kSigning: " . bin2hex($kSigning));
    CommonCloudStorage_Log("最终签名: " . $signature);
    
    // 构建Authorization头 - 添加调试信息
    $authorization = $algorithm . ' ' .
                    'Credential=' . $accessKey . '/' . $credentialScope . ', ' .
                    'SignedHeaders=' . $signedHeaders . ', ' .
                    'Signature=' . $signature;
    
    // 调试日志
    CommonCloudStorage_Log("签名算法调试:");
    CommonCloudStorage_Log("区域设置: " . $region);
    CommonCloudStorage_Log("凭证范围: " . $credentialScope);
    CommonCloudStorage_Log("完整Authorization头: " . $authorization);
    
    return $authorization;
}

/**
 * 获取文件MIME类型
 */
function CommonCloudStorage_GetMimeType($filename) {
    $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
    
    $mimeTypes = array(
        'jpg' => 'image/jpeg',
        'jpeg' => 'image/jpeg',
        'png' => 'image/png',
        'gif' => 'image/gif',
        'webp' => 'image/webp',
        'bmp' => 'image/bmp',
        'svg' => 'image/svg+xml',
        'pdf' => 'application/pdf',
        'doc' => 'application/msword',
        'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
        'xls' => 'application/vnd.ms-excel',
        'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        'zip' => 'application/zip',
        'rar' => 'application/x-rar-compressed',
        'txt' => 'text/plain',
        'html' => 'text/html',
        'css' => 'text/css',
        'js' => 'application/javascript'
    );
    
    return isset($mimeTypes[$ext]) ? $mimeTypes[$ext] : 'application/octet-stream';
}

/**
 * HTTP请求函数
 */
function CommonCloudStorage_HttpRequest($method, $url, $headers = array(), $data = '') {
    $ch = curl_init();
    
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
    
    if (!empty($data)) {
        curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    }
    
    if (!empty($headers)) {
        $httpHeaders = array();
        foreach ($headers as $name => $value) {
            $httpHeaders[] = $name . ': ' . $value;
        }
        curl_setopt($ch, CURLOPT_HTTPHEADER, $httpHeaders);
    }
    
    $response = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    $error = curl_error($ch);
    
    curl_close($ch);
    
    return array(
        'http_code' => $httpCode,
        'body' => $response,
        'error' => $error
    );
}

/**
 * 日志记录函数
 */
function CommonCloudStorage_Log($message) {
    global $zbp;
    
    $logFile = $zbp->path . 'zb_users/plugin/CommonCloudStorage/log.txt';
    $logMessage = '[' . date('Y-m-d H:i:s') . '] ' . $message . "\n";
    
    file_put_contents($logFile, $logMessage, FILE_APPEND | LOCK_EX);
}

?>